﻿using Application.Core.IoC;
using StructureMap;
using StructureMap.Configuration.DSL;
using StructureMap.Pipeline;
using System;
using System.Linq;

namespace Infrastructure.Core.Ioc.StructureMap
{
    public class StructureMapContainer : IIoCContainer
    {
        private Registry _registry;
        private IContainer _container;

        public StructureMapContainer()
        {
            this._registry = new Registry();
        }

        public void Add<TPluginType, TConcreteType>(Lifecycle lifecycle) where TConcreteType : TPluginType
        {
            this._registry.For<TPluginType>(GetLifecyle(lifecycle)).Use<TConcreteType>();
        }

        public void Add(Type pluginType, Type concreteType, Lifecycle lifecycle)
        {
            this._registry.For(pluginType, GetLifecyle(lifecycle)).Use(concreteType);
        }

        public void Add(Type pluginType, object instance, Lifecycle lifecycle)
        {
            this._registry.For(pluginType, GetLifecyle(lifecycle)).Use(instance);
        }

        private ILifecycle GetLifecyle(Lifecycle lifecycle)
        {
            var life = (lifecycle == Lifecycle.Transient)
                ? new TransientLifecycle()
                : (lifecycle == Lifecycle.Singleton ? new SingletonLifecycle() as ILifecycle
                : new UniquePerRequestLifecycle());
            return life;
        }

        public void Config()
        {
            this._registry.For<IIoCContainer>().Use(this).LifecycleIs<SingletonLifecycle>();
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                var types = assembly.GetTypes().Where(t => typeof(IIoCRegistry).IsAssignableFrom(t) && t.IsClass).ToList();
                foreach (var item in types)
                {
                    var register = Activator.CreateInstance(item) as IIoCRegistry;
                    register.Register();
                }
            }

            _container = new Container(_registry);
        }

        public object GetInstance(Type type)
        {
            return _container.GetInstance(type);
        }

        public T GetInstance<T>()
        {
            return _container.GetInstance<T>();
        }

        public T[] GetAllInstance<T>()
        {
            return _container.GetAllInstances<T>().ToArray();
        }
    }
}